<?php

namespace app\devices\service;

use think\admin\Service;
use think\App;
use think\cache\driver\Redis;

/**
 * 箱门数据服务
 * Class BoxService
 * @package app\data\service
 */
class BoxService extends Service
{
    public $box_status = [1=>'正常', 2=>'使用', 3=>'异常',4=>'停用',5=>'损坏'];
    protected $redis;

    public function __construct(App $app)
    {
        $this->redis = new Redis();
        parent::__construct($app);
    }

    /**
     * 获取箱门信息
     * @param int $id
     * @param array $map
     * @param string $field
     * @return array|\think\Model|null
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getBox($id=0, $map=[], $field="")
    {
        $where = [];
        if($id){
            $where['id'] = $id;
        }

        $field = $field?$field:'id as box_id, d_id, box_num, box_type, is_lock, user_id, device_board, board_channel, box_status, user_type';

        return $this->app->db->name("JcgBoxs")->field($field)->where($where)->where($map)->find();
    }

    /**
     * 获取设备(或指定)的所有箱子
     * @param int $d_id
     * @param array $ids
     * @return \think\Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getBoxList(int $d_id, $ids=[])
    {
        $map = [
            'd_id' =>$d_id
        ];
        if($ids){
            $map = ['id', 'in', $ids];
        }

        return $this->app->db->name("JcgBoxs")->field("id as box_id, d_id, box_num, box_type, is_lock, user_id, device_board, board_channel, box_status, user_type")->where($map)->select();
    }

    /**
     * 获取箱柜ID
     * @param $d_id
     * @return int
     */
    public function getBoxId($d_id, $s=0){
        if($s>1){
            return 0;
        }
        $key = "BoxIds:".$d_id;
        $len = $this->redis->handler()->LLEN($key);
        $box_id = 0;
        if($len){
            $box_id = $this->redis->handler()->LPOP($key);
        }else{
            $all_ids = $this->app->db->name("JcgBoxs")->where(['d_id'=>$d_id, 'box_status'=>1, 'is_lock'=>1, 'user_id'=>0, 'user_type'=>0])->column("id");
            if($all_ids){
                shuffle($all_ids);
                $all_ids = array_merge([$key], $all_ids);
                call_user_func_array([$this->redis->handler(), 'lPush'], $all_ids);
                $box_id = $this->redis->handler()->LPOP($key);
            }else{
                return $box_id;
            }
        }
        $flag = true;
        $box_ids = $this->redis->handler()->ZRANGE("orderUseBox".$d_id, 0, -1);
        while ($flag){
            if(in_array($box_id, $box_ids) || $this->redis->get("useBox".$box_id) || $this->redis->get("TjBox".$box_id)){
                $box_id = $this->redis->handler()->LPOP($key)??0;
                if(!$box_id){
                    break;
                }
            }else{
                break;
            }
        }
        return $box_id?$box_id:$this->getBoxId($d_id, $s+1);
    }

    /**
     * 获取箱柜数量
     * @param $map
     * @return int
     */
    public function getBoxNum($map){
        return $this->app->db->name("jcg_boxs")->where($map)->count();
    }

    /**
     * 获取多设备可用箱柜数量
     * @param $d_ids
     * @return array
     */
    public function getDevicesBoxNum($d_ids){
        return $this->app->db->name("jcg_boxs")->where(["box_status"=>1, 'is_lock'=>1])->where("d_id", "in", $d_ids)->group("d_id")->column("count(id)", 'd_id');
    }

    /**
     * 获取多设备箱柜数量
     * @param $d_ids
     * @return array
     */
    public function getBoxNums($d_ids){
        return $this->app->db->name("jcg_boxs")->where("d_id", "in", $d_ids)->group("d_id")->column("count(id) as all_num, count(if(user_id,user_id,null)) as use_num, count(if(is_lock=0 AND user_type=0,user_id,null)) as unlock_num", 'd_id');
    }

    /**
     * 获取同一柜点附近未满的柜子编号
     * @param $store_id
     * @param $d_id
     * @return mixed|string
     */
    public function getNearNotFallDeviceNo($store_id, $d_id){
        $d_ids = DevicesService::instance()->getStoreDId($store_id);
        $list = $this->app->db->name("jcg_boxs")->where(["box_status"=>1, 'is_lock'=>1])->where("d_id", "<>",$d_id)->where("d_id", "in", $d_ids)->group("d_id")->column("count(id)", 'd_id');
        $device_no = '';
        if(count($list)){
            $key = array_rand($list);
            $device_no = $this->app->db->name("jcg_devices")->where("id", $key)->value("device_no");
        }
        return $device_no;
    }

    /**
     * 费用格式化
     * @param array $data 箱格数据
     * @param int $d_id 设备ID
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    function buildData(array &$data, int $fee_id){
        $box_types = [1=>'大柜', 2=>'中柜', 3=>'小柜'];

        $fee = DevicesService::instance()->getDeviceFee($fee_id);
        if($fee && $data){
            $details = json_decode($fee['fee_detail'], true);
            foreach ($data as &$row){
                $row['id'] = $row['box_id'];
                $row['box_num'] = $row['box_num']<10?'0'.$row['box_num']:$row['box_num'];
                $row['fee_price'] = $details[($row['box_type']-1)*5+1]??0;
                $row['fee_type'] = $fee['fee_type'];
                $box_type = $box_types[$row['box_type']]??'';
                if($fee['fee_type']==1){
                    //免费
                    $row['fee_detail'] = [];
                }else if($fee['fee_type']==2){
                    //按次
                    $row['price'] = $row['fee_price'];
                    $row['fee_detail'] = [
                        'title'=>'',
                        'description'=>[
                            '按次收费，不得超过'.$details[($row['box_type']-1)*5+2].'天',
                            $box_type.$row['fee_price'].'元/次',
                            '超过'.$details[($row['box_type']-1)*5+2].'天提取将产生寄存费'.$details[($row['box_type']-1)*5+3].'元/箱/天'
                        ],
                        'price_label'=>'按次收费',
                        'price_describe'=>'支付一次性存包费用'.$row['fee_price'].'元'
                    ];
                }else if($fee['fee_type']==3){
                    //按时
                    $row['price'] = $details[($row['box_type']-1)*6+2];
                    $row['fee_detail'] = [
                        'title'=>'可中途多次开门',
                        'description'=>[
                            '预付'.$details[($row['box_type']-1)*6+1].'元，按时收费',
                            $box_type.$details[($row['box_type']-1)*6+2].'元/小时，1天封顶'.$details[($row['box_type']-1)*6+4].'元',
                            '结束订单后，余额秒退回'
                        ],
                        'price_label'=>'预付金额',
                        'price_describe'=>'按时长收费，结束订单后，剩余金额秒退回'
                    ];
                    $row['fee_price'] = $details[($row['box_type']-1)*6+1];
                    $row['free_hours'] = $details[($row['box_type']-1)*6+3];
                    $row['max_money'] = $details[($row['box_type']-1)*6+4];
                }
                if($row['user_type']){
                    $row['box_status'] = 2;
                    $row['is_lock'] = 1;
                }
                $row['fee_info'] = $row['fee_detail'];
                $row['fee_detail'] = $fee['summary'];
                $row['box_type'] = $box_type;
                unset($row['id']);
                unset($row['user_type']);
            }
        }
    }

    /**
     * 更新用户占用箱子
     * @param $user_id
     * @return int
     * @throws \think\db\exception\DbException
     */
    public function updateBoxs($user_id){
        $box_ids = $this->app->db->name("jcg_devices_order")->where(['user_id'=>$user_id, 'status'=>0])->column("box_id");
        if($box_ids){
            return $this->app->db->name("JcgBoxs")->where('id','in',$box_ids)->update(['box_status'=>1, 'user_id'=>0]);
        }
    }

    public function updateBox($id, $data){
        if($id){
            $res = $this->app->db->name("JcgBoxs")->where("id", $id)->update($data);
            if(!$res){
                $box = $this->app->db->name("JcgBoxs")->where("id", $id)->find();
                if(($data['box_status']??0)==$box['box_status'] && ($data['user_id']??0)==$box['user_id']){
                    return true;
                }
            }
            return $res;
        }else{
            return false;
        }
    }

    /**
     * 商户端费用格式化
     * @param $data
     * @param $user
     */
    public function buildBoxList(&$data=[], $user=[]){
        $order_list = $picks = $users = [];
        if(($user['stores']??[])){
            $map[] = ['store_id', "in", $user['stores']];
            $map[] = ['status', "=", 1];
            $order_list = OrderService::instance()->getOutTimeOrderBoxId($map);

            if($order_list){
                $o_ids = array_column($order_list, "id");
                $u_ids = array_column($order_list, "user_id");

                if($o_ids) {
                    $picks = $this->app->db->name("jcg_device_pickupcode")->where("order_id", "in", $o_ids)->column("mobile, code", "order_id");
                }
                if($u_ids){
                    $users = $this->app->db->name("data_user")->where("id", "in", $u_ids)->column("nickname,phone", "id");
                }
            }
        }

        foreach ($data as &$row){
            $row['user'] = (object)[];
            $status = 2;
            if(isset($order_list[$row['box_id']])){
                $order = $order_list[$row['box_id']];
                $status = $order['out_time']?1:4;

                $row['user'] = [
                    'order_id'=> $order['id'],
                    'nickname'=> $users[$order['user_id']]['nickname']??'',
                    'mobile' => $picks[$order['id']]['mobile']??($users[$order['user_id']]['phone']??''),
                    'code' => $picks[$order['id']]['code']??'',
                    'create_time' => date("Y-m-d H:i",$order['create_time'])
                ];
            }
            $status = $row['user_type']==1?3:$status;
            $row['status'] = $status;
            unset($row['box_status'], $row['user_type']);
        }
    }

}